home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_400 / 419_01 / odmg10 / config / imake.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-16  |  18.9 KB  |  826 lines

  1. /* $XConsortium: imake.c,v 1.65 91/07/25 17:50:17 rws Exp $ */
  2.  
  3. /*****************************************************************************\
  4.  *                                                                           *
  5.  *                                Porting Note                               *
  6.  *                                                                           *
  7.  * Add the value of BOOTSTRAPCFLAGS to the cpp_argv table so that it will be *
  8.  * passed to the template file.                                              *
  9.  *                                                                           *
  10. \*****************************************************************************/
  11.  
  12. /*
  13.  * 
  14.  * Copyright 1985, 1986, 1987 by the Massachusetts Institute of Technology
  15.  * 
  16.  * Permission to use, copy, modify, and distribute this
  17.  * software and its documentation for any purpose and without
  18.  * fee is hereby granted, provided that the above copyright
  19.  * notice appear in all copies and that both that copyright
  20.  * notice and this permission notice appear in supporting
  21.  * documentation, and that the name of M.I.T. not be used in
  22.  * advertising or publicity pertaining to distribution of the
  23.  * software without specific, written prior permission.
  24.  * M.I.T. makes no representations about the suitability of
  25.  * this software for any purpose.  It is provided "as is"
  26.  * without express or implied warranty.
  27.  * 
  28.  * Original Author:
  29.  *    Todd Brunhoff
  30.  *    Tektronix, inc.
  31.  *    While a guest engineer at Project Athena, MIT
  32.  *
  33.  * imake: the include-make program.
  34.  *
  35.  * Usage: imake [-Idir] [-Ddefine] [-T] [-f imakefile ] [-s] [-e] [-v] [make flags]
  36.  *
  37.  * Imake takes a template makefile (Imake.tmpl) and runs cpp on it
  38.  * producing a temporary makefile in /tmp.  It then runs make on
  39.  * this pre-processed makefile.
  40.  * Options:
  41.  *        -D    define.  Same as cpp -D argument.
  42.  *        -I    Include directory.  Same as cpp -I argument.
  43.  *        -T    template.  Designate a template other
  44.  *             than Imake.tmpl
  45.  *        -s[F]    show.  Show the produced makefile on the standard
  46.  *            output.  Make is not run is this case.  If a file
  47.  *            argument is provided, the output is placed there.
  48.  *              -e[F]   execute instead of show; optionally name Makefile F
  49.  *        -v    verbose.  Show the make command line executed.
  50.  *
  51.  * Environment variables:
  52.  *        
  53.  *        IMAKEINCLUDE    Include directory to use in addition to "."
  54.  *        IMAKECPP    Cpp to use instead of /lib/cpp
  55.  *        IMAKEMAKE    make program to use other than what is
  56.  *                found by searching the $PATH variable.
  57.  * Other features:
  58.  *    imake reads the entire cpp output into memory and then scans it
  59.  *    for occurences of "@@".  If it encounters them, it replaces it with
  60.  *    a newline.  It also trims any trailing white space on output lines
  61.  *    (because make gets upset at them).  This helps when cpp expands
  62.  *    multi-line macros but you want them to appear on multiple lines.
  63.  *
  64.  *    The macros MAKEFILE and MAKE are provided as macros
  65.  *    to make.  MAKEFILE is set to imake's makefile (not the constructed,
  66.  *    preprocessed one) and MAKE is set to argv[0], i.e. the name of
  67.  *    the imake program.
  68.  *
  69.  * Theory of operation:
  70.  *   1. Determine the name of the imakefile from the command line (-f)
  71.  *    or from the content of the current directory (Imakefile or imakefile).
  72.  *    Call this <imakefile>.  This gets added to the arguments for
  73.  *    make as MAKEFILE=<imakefile>.
  74.  *   2. Determine the name of the template from the command line (-T)
  75.  *    or the default, Imake.tmpl.  Call this <template>
  76.  *   3. Start up cpp an provide it with three lines of input:
  77.  *        #define IMAKE_TEMPLATE        " <template> "
  78.  *        #define INCLUDE_IMAKEFILE    < <imakefile> >
  79.  *        #include IMAKE_TEMPLATE
  80.  *    Note that the define for INCLUDE_IMAKEFILE is intended for
  81.  *    use in the template file.  This implies that the imake is
  82.  *    useless unless the template file contains at least the line
  83.  *        #include INCLUDE_IMAKEFILE
  84.  *   4. Gather the output from cpp, and clean it up, expanding @@ to
  85.  *    newlines, stripping trailing white space, cpp control lines,
  86.  *    and extra blank lines.  This cleaned output is placed in a
  87.  *    temporary file.  Call this <makefile>.
  88.  *   5. Start up make specifying <makefile> as its input.
  89.  *
  90.  * The design of the template makefile should therefore be:
  91.  *    <set global macros like CFLAGS, etc.>
  92.  *    <include machine dependent additions>
  93.  *    #include INCLUDE_IMAKEFILE
  94.  *    <add any global targets like 'clean' and long dependencies>
  95.  */
  96. #include <stdio.h>
  97. #if (defined(SVR4) || defined(_IBMR2) || defined(SYSV386)) && __STDC__
  98. FILE * fdopen();
  99. #endif
  100. #include <ctype.h>
  101. #ifndef X_NOT_POSIX
  102. #define _POSIX_SOURCE
  103. #endif
  104. #include <sys/types.h>
  105. #include <fcntl.h>
  106. #ifdef X_NOT_POSIX
  107. #include <sys/file.h>
  108. #else
  109. #include <unistd.h>
  110. #endif
  111. #if defined(X_NOT_POSIX) || defined(_POSIX_SOURCE)
  112. #include <signal.h>
  113. #else
  114. #define _POSIX_SOURCE
  115. #include <signal.h>
  116. #undef _POSIX_SOURCE
  117. #endif
  118. #include <sys/stat.h>
  119. #ifndef X_NOT_POSIX
  120. #ifdef _POSIX_SOURCE
  121. #include <sys/wait.h>
  122. #else
  123. #define _POSIX_SOURCE
  124. #include <sys/wait.h>
  125. #undef _POSIX_SOURCE
  126. #endif
  127. #define waitCode(w)    WEXITSTATUS(w)
  128. #define waitSig(w)    WTERMSIG(w)
  129. typedef int        waitType;
  130. #else /* X_NOT_POSIX */
  131. #ifdef SYSV
  132. #define waitCode(w)    (((w) >> 8) & 0x7f)
  133. #define waitSig(w)    ((w) & 0xff)
  134. typedef int        waitType;
  135. #else /* SYSV */
  136. #include <sys/wait.h>
  137. #define waitCode(w)    ((w).w_T.w_Retcode)
  138. #define waitSig(w)    ((w).w_T.w_Termsig)
  139. typedef union wait    waitType;
  140. #endif
  141. #ifndef WIFSIGNALED
  142. #define WIFSIGNALED(w) waitSig(w)
  143. #endif
  144. #ifndef WIFEXITED
  145. #define WIFEXITED(w) waitCode(w)
  146. #endif
  147. #endif /* X_NOT_POSIX */
  148. #ifndef X_NOT_STDC_ENV
  149. #include <stdlib.h>
  150. #else
  151. char *malloc(), *realloc();
  152. void exit();
  153. #endif
  154. #if defined(macII) && !defined(__STDC__)  /* stdlib.h fails to define these */
  155. char *malloc(), *realloc();
  156. #endif /* macII */
  157. #ifdef X_NOT_STDC_ENV
  158. extern char    *getenv();
  159. #endif
  160. #include <errno.h>
  161. extern int    errno;
  162. #include "imakemdep.h"
  163.  
  164.  
  165. #define    TRUE        1
  166. #define    FALSE        0
  167.  
  168. #ifdef FIXUP_CPP_WHITESPACE
  169. int    InRule = FALSE;
  170. #endif
  171.  
  172. /*
  173.  * Some versions of cpp reduce all tabs in macro expansion to a single
  174.  * space.  In addition, the escaped newline may be replaced with a
  175.  * space instead of being deleted.  Blech.
  176.  */
  177. #ifndef FIXUP_CPP_WHITESPACE
  178. #define KludgeOutputLine(arg)
  179. #define KludgeResetRule()
  180. #endif
  181.  
  182. typedef    unsigned char    boolean;
  183.  
  184. #ifndef DEFAULT_CPP
  185. #ifdef USE_CC_E
  186. #define DEFAULT_CPP "/bin/cc"
  187. #else
  188. #ifdef CPP_PROGRAM
  189. #define DEFAULT_CPP CPP_PROGRAM
  190. #else
  191. #define DEFAULT_CPP "/lib/cpp"
  192. #endif
  193. #endif
  194. #endif
  195.  
  196. char *cpp = DEFAULT_CPP;
  197.  
  198. char    *tmpMakefile    = "/tmp/Imf.XXXXXX";
  199. char    *tmpImakefile    = "/tmp/IIf.XXXXXX";
  200. char    *make_argv[ ARGUMENTS ] = { "make" };
  201.  
  202. int    make_argindex;
  203. int    cpp_argindex;
  204. char    *make = NULL;
  205. char    *Imakefile = NULL;
  206. char    *Makefile = "Makefile";
  207. char    *Template = "Imake.tmpl";
  208. char    *program;
  209. char    *FindImakefile();
  210. char    *ReadLine();
  211. char    *CleanCppInput();
  212. char    *Strdup();
  213. char    *Emalloc();
  214.  
  215. boolean    verbose = FALSE;
  216. boolean    show = TRUE;
  217.  
  218. main(argc, argv)
  219.     int    argc;
  220.     char    **argv;
  221. {
  222.     FILE    *tmpfd;
  223.     char    makeMacro[ BUFSIZ ];
  224.     char    makefileMacro[ BUFSIZ ];
  225.  
  226.     program = argv[0];
  227.     init();
  228.     SetOpts(argc, argv);
  229. #ifdef USE_CC_E
  230.     AddCppArg("-");
  231. #endif
  232.  
  233.     Imakefile = FindImakefile(Imakefile);
  234.     if (Makefile)
  235.         tmpMakefile = Makefile;
  236.     else {
  237.         tmpMakefile = Strdup(tmpMakefile);
  238.         (void) mktemp(tmpMakefile);
  239.     }
  240.     AddMakeArg("-f");
  241.     AddMakeArg( tmpMakefile );
  242.     sprintf(makeMacro, "MAKE=%s", program);
  243.     AddMakeArg( makeMacro );
  244.     sprintf(makefileMacro, "MAKEFILE=%s", Imakefile);
  245.     AddMakeArg( makefileMacro );
  246.  
  247.     if ((tmpfd = fopen(tmpMakefile, "w+")) == NULL)
  248.         LogFatal("Cannot create temporary file %s.", tmpMakefile);
  249.  
  250.     cppit(Imakefile, Template, tmpfd, tmpMakefile);
  251.  
  252.     if (show) {
  253.         if (Makefile == NULL)
  254.             showit(tmpfd);
  255.     } else
  256.         makeit();
  257.     wrapup();
  258.     exit(0);
  259. }
  260.  
  261. showit(fd)
  262.     FILE    *fd;
  263. {
  264.     char    buf[ BUFSIZ ];
  265.     int    red;
  266.  
  267.     fseek(fd, 0, 0);
  268.     while ((red = fread(buf, 1, BUFSIZ, fd)) > 0)
  269.         fwrite(buf, red, 1, stdout);
  270.     if (red < 0)
  271.         LogFatal("Cannot write stdout.", "");
  272. }
  273.  
  274. wrapup()
  275. {
  276.     if (tmpMakefile != Makefile)
  277.         unlink(tmpMakefile);
  278.     unlink(tmpImakefile);
  279. }
  280.  
  281. #ifdef SIGNALRETURNSINT
  282. int
  283. #else
  284. void
  285. #endif
  286. catch(sig)
  287.     int    sig;
  288. {
  289.     errno = 0;
  290.     LogFatalI("Signal %d.", sig);
  291. }
  292.  
  293. /*
  294.  * Initialize some variables.
  295.  */
  296. init()
  297. {
  298.     char    *p;
  299.  
  300.     make_argindex=0;
  301.     while (make_argv[ make_argindex ] != NULL)
  302.         make_argindex++;
  303.     cpp_argindex = 0;
  304.     while (cpp_argv[ cpp_argindex ] != NULL)
  305.         cpp_argindex++;
  306.  
  307.     /*
  308.      * See if the standard include directory is different than
  309.      * the default.  Or if cpp is not the default.  Or if the make
  310.      * found by the PATH variable is not the default.
  311.      */
  312.     if (p = getenv("IMAKEINCLUDE")) {
  313.         if (*p != '-' || *(p+1) != 'I')
  314.             LogFatal("Environment var IMAKEINCLUDE %s\n",
  315.                 "must begin with -I");
  316.         AddCppArg(p);
  317.         for (; *p; p++)
  318.             if (*p == ' ') {
  319.                 *p++ = '\0';
  320.                 AddCppArg(p);
  321.             }
  322.     }
  323.     if (p = getenv("IMAKECPP"))
  324.         cpp = p;
  325.     if (p = getenv("IMAKEMAKE"))
  326.         make = p;
  327.  
  328.     if (signal(SIGINT, SIG_IGN) != SIG_IGN)
  329.         signal(SIGINT, catch);
  330. }
  331.  
  332. AddMakeArg(arg)
  333.     char    *arg;
  334. {
  335.     errno = 0;
  336.     if (make_argindex >= ARGUMENTS-1)
  337.         LogFatal("Out of internal storage.", "");
  338.     make_argv[ make_argindex++ ] = arg;
  339.     make_argv[ make_argindex ] = NULL;
  340. }
  341.  
  342. AddCppArg(arg)
  343.     char    *arg;
  344. {
  345.     errno = 0;
  346.     if (cpp_argindex >= ARGUMENTS-1)
  347.         LogFatal("Out of internal storage.", "");
  348.     cpp_argv[ cpp_argindex++ ] = arg;
  349.     cpp_argv[ cpp_argindex ] = NULL;
  350. }
  351.  
  352. SetOpts(argc, argv)
  353.     int    argc;
  354.     char    **argv;
  355. {
  356.     errno = 0;
  357.     /*
  358.      * Now gather the arguments for make
  359.      */
  360.     for(argc--, argv++; argc; argc--, argv++) {
  361.         /*
  362.          * We intercept these flags.
  363.          */
  364.         if (argv[0][0] == '-') {
  365.         if (argv[0][1] == 'D') {
  366.             AddCppArg(argv[0]);
  367.         } else if (argv[0][1] == 'I') {
  368.             AddCppArg(argv[0]);
  369.         } else if (argv[0][1] == 'f') {
  370.             if (argv[0][2])
  371.             Imakefile = argv[0]+2;
  372.             else {
  373.             argc--, argv++;
  374.             if (! argc)
  375.                 LogFatal("No description arg after -f flag\n", "");
  376.             Imakefile = argv[0];
  377.             }
  378.         } else if (argv[0][1] == 's') {
  379.             if (argv[0][2])
  380.             Makefile = ((argv[0][2] == '-') && !argv[0][3]) ?
  381.                 NULL : argv[0]+2;
  382.             else {
  383.             argc--, argv++;
  384.             if (!argc)
  385.                 LogFatal("No description arg after -s flag\n", "");
  386.             Makefile = ((argv[0][0] == '-') && !argv[0][1]) ?
  387.                 NULL : argv[0];
  388.             }
  389.             show = TRUE;
  390.         } else if (argv[0][1] == 'e') {
  391.            Makefile = (argv[0][2] ? argv[0]+2 : NULL);
  392.            show = FALSE;
  393.         } else if (argv[0][1] == 'T') {
  394.             if (argv[0][2])
  395.             Template = argv[0]+2;
  396.             else {
  397.             argc--, argv++;
  398.             if (! argc)
  399.                 LogFatal("No description arg after -T flag\n", "");
  400.             Template = argv[0];
  401.             }
  402.         } else if (argv[0][1] == 'v') {
  403.             verbose = TRUE;
  404.         } else
  405.             AddMakeArg(argv[0]);
  406.         } else
  407.         AddMakeArg(argv[0]);
  408.     }
  409. }
  410.  
  411. char *FindImakefile(Imakefile)
  412.     char    *Imakefile;
  413. {
  414.     int    fd;
  415.  
  416.     if (Imakefile) {
  417.         if ((fd = open(Imakefile, O_RDONLY)) < 0)
  418.             LogFatal("Cannot open %s.", Imakefile);
  419.     } else {
  420.         if ((fd = open("Imakefile", O_RDONLY)) < 0)
  421.             if ((fd = open("imakefile", O_RDONLY)) < 0)
  422.                 LogFatal("No description file.", "");
  423.             else
  424.                 Imakefile = "imakefile";
  425.         else
  426.             Imakefile = "Imakefile";
  427.     }
  428.     close (fd);
  429.     return(Imakefile);
  430. }
  431.  
  432. LogFatalI(s, i)
  433.     char *s;
  434.     int i;
  435. {
  436.     /*NOSTRICT*/
  437.     LogFatal(s, (char *)i);
  438. }
  439.  
  440. LogFatal(x0,x1)
  441.     char *x0, *x1;
  442. {
  443.     extern char    *sys_errlist[];
  444.     static boolean    entered = FALSE;
  445.  
  446.     if (entered)
  447.         return;
  448.     entered = TRUE;
  449.  
  450.     fprintf(stderr, "%s: ", program);
  451.     if (errno)
  452.         fprintf(stderr, "%s: ", sys_errlist[ errno ]);
  453.     fprintf(stderr, x0,x1);
  454.     fprintf(stderr, "  Stop.\n");
  455.     wrapup();
  456.     exit(1);
  457. }
  458.  
  459. showargs(argv)
  460.     char    **argv;
  461. {
  462.     for (; *argv; argv++)
  463.         fprintf(stderr, "%s ", *argv);
  464.     fprintf(stderr, "\n");
  465. }
  466.  
  467. cppit(Imakefile, template, outfd, outfname)
  468.     char    *Imakefile;
  469.     char    *template;
  470.     FILE    *outfd;
  471.     char    *outfname;
  472. {
  473.     FILE    *pipeFile;
  474.     int    pid, pipefd[2];
  475.     waitType    status;
  476.     char    *cleanedImakefile;
  477.  
  478.     /*
  479.      * Get a pipe.
  480.      */
  481.     if (pipe(pipefd) < 0)
  482.         LogFatal("Cannot make a pipe.", "");
  483.  
  484.     /*
  485.      * Fork and exec cpp
  486.      */
  487.     pid = fork();
  488.     if (pid < 0)
  489.         LogFatal("Cannot fork.", "");
  490.     if (pid) {    /* parent */
  491.         close(pipefd[0]);
  492.         cleanedImakefile = CleanCppInput(Imakefile);
  493.         if ((pipeFile = fdopen(pipefd[1], "w")) == NULL)
  494.             LogFatalI("Cannot fdopen fd %d for output.", pipefd[1]);
  495.         fprintf(pipeFile, "#define IMAKE_TEMPLATE\t\"%s\"\n",
  496.             template);
  497.         fprintf(pipeFile, "#define INCLUDE_IMAKEFILE\t<%s>\n",
  498.             cleanedImakefile);
  499.         fprintf(pipeFile, "#include IMAKE_TEMPLATE\n");
  500.         fclose(pipeFile);
  501.         while (wait(&status) > 0) {
  502.             errno = 0;
  503.             if (WIFSIGNALED(status))
  504.                 LogFatalI("Signal %d.", waitSig(status));
  505.             if (WIFEXITED(status) && waitCode(status))
  506.                 LogFatalI("Exit code %d.", waitCode(status));
  507.         }
  508.         CleanCppOutput(outfd, outfname);
  509.     } else {    /* child... dup and exec cpp */
  510.         if (verbose)
  511.             showargs(cpp_argv);
  512.         dup2(pipefd[0], 0);
  513.         dup2(fileno(outfd), 1);
  514.         close(pipefd[1]);
  515.         execv(cpp, cpp_argv);
  516.         LogFatal("Cannot exec %s.", cpp);
  517.     }
  518. }
  519.  
  520. makeit()
  521. {
  522.     int    pid;
  523.     waitType    status;
  524.  
  525.     /*
  526.      * Fork and exec make
  527.      */
  528.     pid = fork();
  529.     if (pid < 0)
  530.         LogFatal("Cannot fork.", "");
  531.     if (pid) {    /* parent... simply wait */
  532.         while (wait(&status) > 0) {
  533.             errno = 0;
  534.             if (WIFSIGNALED(status))
  535.                 LogFatalI("Signal %d.", waitSig(status));
  536.             if (WIFEXITED(status) && waitCode(status))
  537.                 LogFatalI("Exit code %d.", waitCode(status));
  538.         }
  539.     } else {    /* child... dup and exec cpp */
  540.         if (verbose)
  541.             showargs(make_argv);
  542.         if (make)
  543.             execv(make, make_argv);
  544.         else
  545.             execvp("make", make_argv);
  546.         LogFatal("Cannot exec %s.", make);
  547.     }
  548. }
  549.  
  550. char *CleanCppInput(Imakefile)
  551.     char    *Imakefile;
  552. {
  553.     FILE    *outFile = NULL;
  554.     int    infd;
  555.     char    *buf,        /* buffer for file content */
  556.         *pbuf,        /* walking pointer to buf */
  557.         *punwritten,    /* pointer to unwritten portion of buf */
  558.         *cleanedImakefile = Imakefile,    /* return value */
  559.         *ptoken,    /* pointer to # token */
  560.         *pend,        /* pointer to end of # token */
  561.         savec;        /* temporary character holder */
  562.     struct stat    st;
  563.  
  564.     /*
  565.      * grab the entire file.
  566.      */
  567.     if ((infd = open(Imakefile, O_RDONLY)) < 0)
  568.         LogFatal("Cannot open %s for input.", Imakefile);
  569.     fstat(infd, &st);
  570.     buf = Emalloc(st.st_size+1);
  571.     if (read(infd, buf, st.st_size) != st.st_size)
  572.         LogFatal("Cannot read all of %s:", Imakefile);
  573.     close(infd);
  574.     buf[ st.st_size ] = '\0';
  575.  
  576.     punwritten = pbuf = buf;
  577.     while (*pbuf) {
  578.         /* pad make comments for cpp */
  579.         if (*pbuf == '#' && (pbuf == buf || pbuf[-1] == '\n')) {
  580.  
  581.         ptoken = pbuf+1;
  582.         while (*ptoken == ' ' || *ptoken == '\t')
  583.             ptoken++;
  584.         pend = ptoken;
  585.         while (*pend && *pend != ' ' && *pend != '\t' && *pend != '\n')
  586.             pend++;
  587.         savec = *pend;
  588.         *pend = '\0';
  589.         if (strcmp(ptoken, "include")
  590.          && strcmp(ptoken, "define")
  591.          && strcmp(ptoken, "undef")
  592.          && strcmp(ptoken, "ifdef")
  593.          && strcmp(ptoken, "ifndef")
  594.          && strcmp(ptoken, "else")
  595.          && strcmp(ptoken, "endif")
  596.          && strcmp(ptoken, "if")) {
  597.             if (outFile == NULL) {
  598.             tmpImakefile = Strdup(tmpImakefile);
  599.             (void) mktemp(tmpImakefile);
  600.             cleanedImakefile = tmpImakefile;
  601.             outFile = fopen(tmpImakefile, "w");
  602.             if (outFile == NULL)
  603.                 LogFatal("Cannot open %s for write.\n",
  604.                 tmpImakefile);
  605.             }
  606.             fwrite(punwritten, sizeof(char), pbuf-punwritten, outFile);
  607.             fputs("/**/", outFile);
  608.             punwritten = pbuf;
  609.         }
  610.         *pend = savec;
  611.         }
  612.         pbuf++;
  613.     }
  614.     if (outFile) {
  615.         fwrite(punwritten, sizeof(char), pbuf-punwritten, outFile);
  616.         fclose(outFile); /* also closes the pipe */
  617.     }
  618.  
  619.     return(cleanedImakefile);
  620. }
  621.  
  622. CleanCppOutput(tmpfd, tmpfname)
  623.     FILE    *tmpfd;
  624.     char    *tmpfname;
  625. {
  626.     char    *input;
  627.     int    blankline = 0;
  628.  
  629.     while(input = ReadLine(tmpfd, tmpfname)) {
  630.         if (isempty(input)) {
  631.             if (blankline++)
  632.                 continue;
  633.             KludgeResetRule();
  634.         } else {
  635.             blankline = 0;
  636.             KludgeOutputLine(&input);
  637.             fputs(input, tmpfd);
  638.         }
  639.         putc('\n', tmpfd);
  640.     }
  641.     fflush(tmpfd);
  642. #ifdef NFS_STDOUT_BUG
  643.     /*
  644.      * On some systems, NFS seems to leave a large number of nulls at
  645.      * the end of the file.  Ralph Swick says that this kludge makes the
  646.      * problem go away.
  647.      */
  648.     ftruncate (fileno(tmpfd), (off_t)ftell(tmpfd));
  649. #endif
  650. }
  651.  
  652. /*
  653.  * Determine of a line has nothing in it.  As a side effect, we trim white
  654.  * space from the end of the line.  Cpp magic cookies are also thrown away.
  655.  */
  656. isempty(line)
  657.     char    *line;
  658. {
  659.     char    *pend;
  660.  
  661.     /*
  662.      * Check for lines of the form
  663.      *    # n "...
  664.      * or
  665.      *    # line n "...
  666.      */
  667.     if (*line == '#') {
  668.         pend = line+1;
  669.         if (*pend == ' ')
  670.             pend++;
  671.         if (strncmp(pend, "line ", 5) == 0)
  672.             pend += 5;
  673.         if (isdigit(*pend)) {
  674.             while (isdigit(*pend))
  675.                 pend++;
  676.             if (*pend++ == ' ' && *pend == '"')
  677.                 return(TRUE);
  678.         }
  679.     }
  680.  
  681.     /*
  682.      * Find the end of the line and then walk back.
  683.      */
  684.     for (pend=line; *pend; pend++) ;
  685.  
  686.     pend--;
  687.     while (pend >= line && (*pend == ' ' || *pend == '\t'))
  688.         pend--;
  689.     *++pend = '\0';
  690.     return (*line == '\0');
  691. }
  692.  
  693. /*ARGSUSED*/
  694. char *ReadLine(tmpfd, tmpfname)
  695.     FILE    *tmpfd;
  696.     char    *tmpfname;
  697. {
  698.     static boolean    initialized = FALSE;
  699.     static char    *buf, *pline, *end;
  700.     char    *p1, *p2;
  701.  
  702.     if (! initialized) {
  703.         int    total_red;
  704.         struct stat    st;
  705.  
  706.         /*
  707.          * Slurp it all up.
  708.          */
  709.         fseek(tmpfd, 0, 0);
  710.         fstat(fileno(tmpfd), &st);
  711.         pline = buf = Emalloc(st.st_size+1);
  712.         total_red = read(fileno(tmpfd), buf, st.st_size);
  713.         if (total_red != st.st_size)
  714.             LogFatal("cannot read %s\n", tmpMakefile);
  715.         end = buf + st.st_size;
  716.         *end = '\0';
  717.         lseek(fileno(tmpfd), 0, 0);
  718. #ifdef SYSV
  719.         freopen(tmpfname, "w+", tmpfd);
  720. #else    /* !SYSV */
  721.         ftruncate(fileno(tmpfd), 0);
  722. #endif    /* !SYSV */
  723.         initialized = TRUE;
  724.         fprintf (tmpfd, "# Makefile generated by imake - do not edit!\n");
  725.         fprintf (tmpfd, "# %s\n",
  726.         "$XConsortium: imake.c,v 1.65 91/07/25 17:50:17 rws Exp $");
  727.  
  728. #ifdef FIXUP_CPP_WHITESPACE
  729.         {
  730.         static char *cpp_warning[] = {
  731. "#",
  732. "# The cpp used on this machine replaces all newlines and multiple tabs and",
  733. "# spaces in a macro expansion with a single space.  Imake tries to compensate",
  734. "# for this, but is not always successful.",
  735. "#",
  736. NULL };
  737.         char **cpp;
  738.  
  739.         for (cpp = cpp_warning; *cpp; cpp++) {
  740.             fprintf (tmpfd, "%s\n", *cpp);
  741.         }
  742.         }
  743. #endif /* FIXUP_CPP_WHITESPACE */
  744.     }
  745.  
  746.     for (p1 = pline; p1 < end; p1++) {
  747.         if (*p1 == '@' && *(p1+1) == '@') { /* soft EOL */
  748.             *p1++ = '\0';
  749.             p1++; /* skip over second @ */
  750.             break;
  751.         }
  752.         else if (*p1 == '\n') { /* real EOL */
  753.             *p1++ = '\0';
  754.             break;
  755.         }
  756.     }
  757.  
  758.     /*
  759.      * return NULL at the end of the file.
  760.      */
  761.     p2 = (pline == p1 ? NULL : pline);
  762.     pline = p1;
  763.     return(p2);
  764. }
  765.  
  766. writetmpfile(fd, buf, cnt)
  767.     FILE    *fd;
  768.     int    cnt;
  769.     char    *buf;
  770. {
  771.     errno = 0;
  772.     if (fwrite(buf, cnt, 1, fd) != 1)
  773.         LogFatal("Cannot write to %s.", tmpMakefile);
  774. }
  775.  
  776. char *Emalloc(size)
  777.     int    size;
  778. {
  779.     char    *p;
  780.  
  781.     if ((p = malloc(size)) == NULL)
  782.         LogFatalI("Cannot allocate %d bytes\n", size);
  783.     return(p);
  784. }
  785.  
  786. #ifdef FIXUP_CPP_WHITESPACE
  787. KludgeOutputLine(pline)
  788.     char    **pline;
  789. {
  790.     char    *p = *pline;
  791.  
  792.     switch (*p) {
  793.         case '#':    /*Comment - ignore*/
  794.         break;
  795.         case '\t':    /*Already tabbed - ignore it*/
  796.             break;
  797.         case ' ':    /*May need a tab*/
  798.         default:
  799.         for (; *p; p++) if (p[0] == ':' && 
  800.                     p > *pline && p[-1] != '\\') {
  801.             if (**pline == ' ')
  802.             (*pline)++;
  803.             InRule = TRUE;
  804.             break;
  805.         }
  806.         if (InRule && **pline == ' ')
  807.             **pline = '\t';
  808.         break;
  809.     }
  810. }
  811.  
  812. KludgeResetRule()
  813. {
  814.     InRule = FALSE;
  815. }
  816. #endif /* FIXUP_CPP_WHITESPACE */
  817.  
  818. char *Strdup(cp)
  819.     register char *cp;
  820. {
  821.     register char *new = Emalloc(strlen(cp) + 1);
  822.  
  823.     strcpy(new, cp);
  824.     return new;
  825. }
  826.